﻿using System.Diagnostics;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;

namespace LibClone
{
	internal class Program
	{

		static async Task<string> CreateRepository(string name, string? organization = null)
		{
			HttpClient httpClient = new();
			// 配置 GOGS 连接信息
			string baseUrl = "https://gogs.jklqm.space:2443"; // 替换为你的 GOGS 地址
			string accessToken = "f08f290332fc3422225f4c5a423b55990b803ce7";        // 替换为你的访问令牌

			httpClient.BaseAddress = new Uri(baseUrl);
			httpClient.DefaultRequestHeaders.Authorization =
					new AuthenticationHeaderValue("token", accessToken);
			// 构建 API 端点
			string endpoint = organization != null
				? $"/api/v1/org/{organization}/repos"   // 组织仓库
				: "/api/v1/user/repos";                  // 个人仓库

			// 准备请求数据
			var requestBody = new
			{
				name,
				description = "Created via API",
				@private = false
			};

			var json = JsonSerializer.Serialize(requestBody);
			var content = new StringContent(json, Encoding.UTF8, "application/json");

			// 发送请求
			var response = await httpClient.PostAsync(endpoint, content);
			var responseBody = await response.Content.ReadAsStringAsync();

			if (!response.IsSuccessStatusCode)
			{
				HandleErrorResponse(response.StatusCode, responseBody);
			}

			// 解析响应获取仓库 URL
			var result = JsonSerializer.Deserialize<JsonElement>(responseBody);
			string final;
			if (result.TryGetProperty("clone_url", out var clone_url))
				final = clone_url.GetString() ?? throw new Exception();
			else if (result.TryGetProperty("ssh_url", out var ssh_url))
				final = ssh_url.GetString() ?? throw new Exception();
			else
				throw new Exception();
			return final;
		}

		static void HandleErrorResponse(System.Net.HttpStatusCode statusCode, string body)
		{
			string message = statusCode switch
			{
				System.Net.HttpStatusCode.NotFound => "API endpoint not found (404). Possible issues:\n" +
													  "1. Incorrect URL structure\n" +
													  "2. GOGS version mismatch\n" +
													  "3. Organization libName misspelled",

				System.Net.HttpStatusCode.Unauthorized => "Invalid access token (401)",

				System.Net.HttpStatusCode.Forbidden => "Permission denied (403). " +
													   "Ensure your account has repo creation rights in the organization",

				_ => $"API returned error: {statusCode} - {body}"
			};

			throw new ApplicationException(message);
		}
		public static bool CopyFolder(
			string sourceFolder,
			string destFolder,
			bool overwrite = false,
			bool preserveAttributes = true,
			Action<int, int, string>? progressCallback = null,
			string[]? excludeExtensions = null,
			string[]? includeExtensions = null)
		{
			try
			{
				// 验证源文件夹
				if (!Directory.Exists(sourceFolder))
				{
					throw new DirectoryNotFoundException($"Source directory not found: {sourceFolder}");
				}

				// 创建目标文件夹（包括所有中间目录）
				Directory.CreateDirectory(destFolder);

				// 获取所有文件（考虑过滤选项）
				string[] files = Directory.GetFiles(sourceFolder, "*", SearchOption.AllDirectories);
				int totalFiles = files.Length;
				int filesCopied = 0;

				// 文件过滤函数
				Func<string, bool> shouldCopy = file =>
				{
					string ext = Path.GetExtension(file)?.ToLower();

					if (excludeExtensions != null && excludeExtensions.Contains(ext))
						return false;

					if (includeExtensions != null && !includeExtensions.Contains(ext))
						return false;

					return true;
				};

				// 递归拷贝文件
				foreach (string sourceFile in files)
				{
					if (!shouldCopy(sourceFile))
					{
						filesCopied++;
						continue;
					}

					// 构建目标文件路径
					string relativePath = Path.GetRelativePath(sourceFolder, sourceFile);
					string destFile = Path.Combine(destFolder, relativePath);

					// 创建目标目录
					string destDir = Path.GetDirectoryName(destFile) ?? throw new Exception();
					Directory.CreateDirectory(destDir);

					// 拷贝文件
					File.Copy(sourceFile, destFile, overwrite);

					// 保留属性
					if (preserveAttributes)
					{
						var sourceInfo = new FileInfo(sourceFile);
						var destInfo = new FileInfo(destFile);

						destInfo.Attributes = sourceInfo.Attributes;
						destInfo.CreationTime = sourceInfo.CreationTime;
						destInfo.LastWriteTime = sourceInfo.LastWriteTime;
						destInfo.LastAccessTime = sourceInfo.LastAccessTime;
					}

					filesCopied++;
					progressCallback?.Invoke(filesCopied, totalFiles, Path.GetFileName(sourceFile));
				}

				return true;
			}
			catch (Exception ex)
			{
				Console.WriteLine($"⚠️ Error copying folder: {ex.Message}");
				if (ex is UnauthorizedAccessException)
				{
					Console.WriteLine("Permission denied. Try running as administrator.");
				}
				else if (ex is PathTooLongException)
				{
					Console.WriteLine("Path too long. Enable long paths in Windows settings.");
				}
				return false;
			}
		}
		private static bool RunGitCommand(
			string arguments,
			string workingDirectory,
			Action<string>? progressReporter = null)
		{
			try
			{
				using var process = new Process
				{
					StartInfo = new ProcessStartInfo
					{
						FileName = "C:\\Program Files\\Git\\cmd\\git.exe",
						Arguments = arguments,
						WorkingDirectory = workingDirectory,
						UseShellExecute = false,
						RedirectStandardOutput = true,
						RedirectStandardError = true,
						CreateNoWindow = true
					}
				};

				process.OutputDataReceived += (sender, e) =>
				{
					if (!string.IsNullOrWhiteSpace(e.Data))
						progressReporter?.Invoke(e.Data);
				};

				process.ErrorDataReceived += (sender, e) =>
				{
					if (!string.IsNullOrWhiteSpace(e.Data))
						progressReporter?.Invoke($"[ERROR] {e.Data}");
				};

				process.Start();
				process.BeginOutputReadLine();
				process.BeginErrorReadLine();

				// 等待执行完成（带超时）
				if (!process.WaitForExit(60 * 1000)) // 60秒超时
				{
					progressReporter?.Invoke("⚠️ Git command timed out");
					process.Kill();
					return false;
				}

				return process.ExitCode == 0;
			}
			catch (Exception ex)
			{
				progressReporter?.Invoke($"❌ Error running git command: {ex.Message}");
				return false;
			}
		}

		private static void CloneLib(string prmPath, string remoteUrl)
		{
			string libName = Path.GetFileName(prmPath);
			string newLibPath = $"{Directory.GetCurrentDirectory()}\\..\\{libName}";
			Directory.CreateDirectory(newLibPath);
			bool success = CopyFolder(
				prmPath,
				newLibPath,
				overwrite: true, // 覆盖现有文件
				preserveAttributes: true, // 保留文件属性
				progressCallback: (current, total, fileName) =>
				{
					//Console.WriteLine($"Copying ({current}/{total}): {fileName}");
				});
			if (!RunGitCommand($"init \"{newLibPath}\"", newLibPath))
			{
				throw new Exception();
			}
			if (!RunGitCommand($"remote add origin {remoteUrl}", newLibPath))
			{
				throw new Exception();
			}
			if (!RunGitCommand($"add .", newLibPath))
			{
				throw new Exception();
			}
			if (!RunGitCommand($"commit -m \"第一次提交\"", newLibPath))
			{
				throw new Exception();
			}
			if (!RunGitCommand($"push -u origin master", newLibPath) && !RunGitCommand($"push -f -u origin master", newLibPath))
			{
				throw new Exception();
			}

		}
		public static void Main(string[] args)
		{
			var hasLib = new HashSet<string>();
			foreach (var i in Directory.GetDirectories("..", "*", SearchOption.TopDirectoryOnly))
			{
				var name = Path.GetFileName(i);
				if (name.StartsWith('.'))
					continue;
				if (name == "Tools")
					continue;
				hasLib.Add(name);
			}
			string orgLibPath = args[^1];
			FileStream stream = new(Path.Combine(orgLibPath, "library.json"), FileMode.Open);
			var lib = JsonSerializer.Deserialize<Libaray>(stream) ?? throw new Exception();
			stream.Close();
			if (lib.dependencies != null)
			{
				foreach (var i in lib.dependencies)
				{
					if (!hasLib.Contains(i.name))
					{
						throw new Exception();
					}
				}
			}
			string libName = Path.GetFileName(orgLibPath);
			var remoteUrl = CreateRepository(libName, "Esp").Result;
			CloneLib(orgLibPath, remoteUrl);
			var gitmodules = new FileStream("..\\.gitmodules", FileMode.Append);
			var data = Encoding.UTF8.GetBytes($"\r\n[submodule \"{libName}\"]\r\n\tpath = {libName}\r\n\turl = {remoteUrl}\r\n\tbranch = master\r\n");
			gitmodules.Write(data, 0, data.Length);
			gitmodules.Flush();
			gitmodules.Close();
			RunGitCommand($"add .", "..");
			RunGitCommand($"commit -m \"添加库:{libName}\"", "..");
			RunGitCommand($"push -f -u origin master", "..");
			//CloneLib(orgLibPath, $"https://gogs.jklqm.space:2443/Esp/{libName}.git");
		}
	}
}
